#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "progressviewer.h"

#include "quizdemowidget.h"

//_______________________________________________________Initial Set up Stuff________________________________________________________________________

/** Constructor
 * Creates a connection to the webcam, and attempts to get a frame
 * from it. Does extensive error checking, giving informative error
 * messages to the user if any of the steps fail. Then reads in the
 * search database file. Finally it sets all the boolean variables
 * and starts the QTimer (which deals with all webcam playing/recording).
 */
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow)
{
    // set program to close when main window is closed.
    // both attributes seem necessary
    setAttribute(Qt::WA_QuitOnClose, true);
    setAttribute(Qt::WA_DeleteOnClose, true);

    ui->setupUi(this);
    //hide toolbar initially
    ui->toolBar->hide();

    // initial configuration: welcome at top, webcam at bottom.
    // this is so window displays in reasonable state if no webcam
    ui->stackedWidget_top->setCurrentIndex(7);
    ui->stackedWidget_bottom->setCurrentIndex(1);

    // show us
    show();

    //create camera object
    camera = cvCreateCameraCapture(0);
    hasCamera = true;

    //check its working
    if(camera == NULL)
    {
        //Error checking========================================
        QMessageBox msgBox;
        msgBox.setText("No webcam detected!");
        msgBox.setInformativeText("Continue without webcam? Some features will be disabled.");
        msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
        msgBox.setDefaultButton(QMessageBox::Yes);
        msgBox.setIcon(QMessageBox::Critical);
        QString detail = "Another program may be using the webcam.\n";
        detail += "The webcam might not be correctly installed\n";
        detail += "Two copies of this program might be running.";
        msgBox.setDetailedText(detail);
        int ret = msgBox.exec();
        if(ret == QMessageBox::Yes)
        {
            hasCamera = false;
        }
        else
        {
            // terminate the program
            close();
            return;
        }

        //End Error checking====================================
    }
    if(hasCamera)
    {
        //get a frame from camera
        IplImage * image=cvQueryFrame(camera);
        //check that it was successfull
        if(image == NULL)
        {
            //Error checking========================================
            QMessageBox msgBox;
            msgBox.setText("Failed to retrieve a video frame from camera!");
            msgBox.setInformativeText("See details for more information.");
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.setDefaultButton(QMessageBox::Ok);
            msgBox.setIcon(QMessageBox::Critical);
            QString detail = "The program could not retrieve any video frames from the systems "
                             "webcam. This could be caused by a faulty or intermittant webcamera. "
                             "Make sure that your webcam is plugged in and properly functional and "
                             "then try to start the program again.";
            msgBox.setDetailedText(detail);
            msgBox.exec();
            //run assertion which will close the program in an error code, specifying where the error occured.
            assert(image);
            //End Error checking====================================
        }
    }

    //Setup variables
    flashRecordingSquare = true;
    buildingVideo = false;
    vidQuality = 50;
    frameRate = 25;
    maxTime = 15;
    frameExtension = ".jpg";
    state = welcomeState;

    dir = QDir::currentPath(); //get current working directory path and set default video and image

#ifdef _WIN32
    userVideo_filename =  "Temp_Video.wmv";
#else
    userVideo_filename =  "Temp_Video.mpg";
#endif

    //start timer
    timer = new QTimer(this);

    //make instance of search engine
    searchEngine.hide();
    searchEngine.startConnections();

    //preferences
    preferenceWindow.hide();
    uip.setupUi(&preferenceWindow);
    uip.retranslateUi(&preferenceWindow);
    preferenceWindow.setWindowModality(Qt::ApplicationModal);

    //about box
    aboutBox.hide();
    uia.setupUi(&aboutBox);
    uia.retranslateUi(&aboutBox);
    aboutBox.setWindowModality(Qt::ApplicationModal);

    //Setup starting state
    setState(welcomeState);

    // not in lesson mode to start
    withinLesson = false;

    createMenu();
    //create status bar
    createStatusBar();

    //initiate process
    ffmpeg = new QProcess(this);

    // init quiz widget
    quizWidget = 0;


    //create the recognition areas
    gesturesEnabled = true;
    gestureTopLeft = new GestureRecognition(0, 20, 20, 80, 80);
    gestureTopRight = new GestureRecognition(1, 540, 20, 80, 80);    


    // construct the back end
    init();
    // construct connections
    startConnections();



}

// initialise backend
void MainWindow::init()
{
    QString filename = "lessons/";
    QFileInfo fn;
    // open lesson directory
    fn.setFile(filename);
    if (fn.isDir()) // assert that it is a directory
    {
        // get .xml files
        QStringList files = QDir(filename).entryList(QStringList("*.xml"));
        // for each xml file
        foreach (QString str, files)
        {
            // create lesson from xml file
            Lesson newLesson;
            newLesson.fromXML(filename + str);
            //qDebug() << (filename + str) << endl;
            //add to lesson list (copy made)
            lessons.append(newLesson);
        }
    }

    for (QList<Lesson>::iterator it = lessons.begin(); it != lessons.end(); ++it) {
        // feed synonyms to thesaurus
        thesaurus.populate(*it);
    }
    // add all phrases to master phrase list. this is used
    // to locate phrases independently of lessons
    for (QList<Lesson>::iterator it = lessons.begin(); it != lessons.end(); ++it) {
        QMutableListIterator<Phrase> mutableIt(*it);
        while (mutableIt.hasNext()) {
            Phrase& p = mutableIt.next();
            //p.setLesson(it->getName());
            phrases.append(p);
        }
/*        foreach (Phrase p, *it) {
            phrases.append(p);
        }*/
    }

    foreach (Phrase p, phrases) {
        qDebug() << p.getLesson();
    }

    // generate actions for lessons
    QAction* newLesson;
    for (QList<Lesson>::iterator it = lessons.begin(); it != lessons.end(); ++it)
    {
        newLesson = new QAction(it->getName(), this);
        // path to lesson icon is relative to root for flexibility
        newLesson->setIcon(QIcon(QString("icons/").append(it->getIcon())));
        connect(newLesson, SIGNAL(triggered()), this, SLOT(lessonSelected()));
        ui->menuLesson->addAction(newLesson);
        newLesson->setStatusTip(it->getDescription());
        lessonActions.append(newLesson);
    }

    // set first lesson to be current lesson
    currentLesson = lessons.end();
    // and first phrase to be current phrase
    //currentPhrase = currentLesson->begin();
    // set a valid phrase, to be safe
    currentPhrase = lessons[0].begin();

    //quizIconWidget = 0;

    //clear temp folders out
    QDir directory(QDir::current());
    //if the directory exists, delete its contents
    if(directory.exists("temp"))
    {
        clearTempDir();
    }else
    {//otherwise create it.
        directory.mkdir("temp");
    }

    signInUser("Guest");
}

/* StartConnections Method
 * This method sets up the connection between all the signals and slots,
 * as well as setting up the widgets
 */
void MainWindow::startConnections()
{
    //make camera widget
    webcam = new WebcamVideoPlayer(this);
    webcam->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    ui->webcamLayout2->addWidget(webcam);

    //make gesture recognition connections
    connect(gestureTopLeft,SIGNAL(gestureDetected(int)),this, SLOT(gestureDetected(int)));
    connect(gestureTopRight,SIGNAL(gestureDetected(int)),this, SLOT(gestureDetected(int)));


    // create MediaObject which encapsulates video
    clip = new Phonon::MediaObject(this);
    path = Phonon::createPath(clip, ui->phononWidget1);

    // scale and maintain aspect ratio
     ui->phononWidget1->setScaleMode(Phonon::VideoWidget::FitInView);

    //Make Button Connections
    connect(ui->playDemoButton, SIGNAL(clicked()),this,SLOT(play()));
    connect(ui->stopDemoButton, SIGNAL(clicked()),this,SLOT(stop()));
    connect(ui->stopRecordingButton, SIGNAL(clicked()),this,SLOT(stop()));
    connect(ui->recordOption, SIGNAL(clicked()),this,SLOT(record()));
    connect(ui->continueOption,SIGNAL(clicked()), this, SLOT(comparing()));
    connect(ui->compareAgainButton,SIGNAL(clicked()), this, SLOT(comparing()));
    connect(ui->playCartoonButton, SIGNAL(clicked()), this, SLOT(play()));
    connect(ui->replayOption, SIGNAL(clicked()), this, SLOT(replayInstructor()));
    connect(ui->stackedWidget_top, SIGNAL(clicked()), this, SLOT(topStackClicked()));
    connect(ui->happyText, SIGNAL(clicked()), this, SLOT(rating_happy()));
    connect(ui->happyButton, SIGNAL(clicked()), this, SLOT(rating_happy()));
    connect(ui->sadText, SIGNAL(clicked()), this, SLOT(rating_sad()));
    connect(ui->sadButton, SIGNAL(clicked()), this, SLOT(rating_sad()));
    connect(ui->okText, SIGNAL(clicked()), this, SLOT(rating_ok()));
    connect(ui->okButton, SIGNAL(clicked()), this, SLOT(rating_ok()));
    connect(ui->cartoon1, SIGNAL(clicked()), this, SLOT(play()));

    //search window
    connect(searchEngine.okButton, SIGNAL(clicked()),this,SLOT(okClicked()));

    //preference window
    connect(uip.showHorizontally, SIGNAL(stateChanged(int)), this, SLOT(changeView()));
    connect(uip.qualitySlider, SIGNAL(valueChanged(int)), this, SLOT(videoQualityChanged(int)));
    connect(uip.frameRateBox, SIGNAL(valueChanged(int)), this, SLOT(videoFrameRateChanged(int)));
    connect(uip.formatBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(videoFrameFormatChanged(QString)));
    connect(uip.recordingLengthBox, SIGNAL(valueChanged(int)), this, SLOT(maxRecordingLengthChanged(int)));
    connect(&preferenceWindow, SIGNAL(finished(int)), this, SLOT(preferencesClosed(int)));
    connect(uip.gestureRecognitionCheckBox, SIGNAL(toggled(bool)), this, SLOT(gesturesEnabledChanged(bool)));
    connect(uip.sensitivitySpinBox, SIGNAL(valueChanged(double)),this,SLOT(sensitivityChanged(double)));

    //user control window
   // connect(cousersDialog, SIGNAL(userCollectionChanged()), usersDialog, SLOT(saveUsers()));

    //Make menu button connections
    connect(ui->actionOpen_Lesson, SIGNAL(triggered()), this, SLOT(openLesson()));
    connect(ui->actionSearch, SIGNAL(activated()), this, SLOT(find()));
    connect(ui->actionPlay_demo_video, SIGNAL(triggered()), this, SLOT(replayInstructor()));
    connect(ui->actionRecord_me, SIGNAL(triggered()), this, SLOT(record()));
    connect(ui->actionSee_cartoon, SIGNAL(triggered()), this, SLOT(showCartoon()));
    connect(ui->actionCompare_my_video, SIGNAL(triggered()), this, SLOT(comparing()));
    connect(ui->actionPreferences, SIGNAL(triggered()), this, SLOT(showPreferences()));
    connect(ui->actionSwitch_user, SIGNAL(triggered()), this, SLOT(userAccountClicked()));
    connect(ui->actionReview_Progress, SIGNAL(triggered()), this, SLOT(openProgressViewerFiltered()));
    connect(ui->actionProgress_report, SIGNAL(triggered()), this, SLOT(openProgressViewer()));
    connect(ui->actionSkip_Phrase, SIGNAL(triggered()), this, SLOT(skipPhrase()));
    connect(ui->actionPrevious_Phrase, SIGNAL(triggered()), this, SLOT(previousPhrase()));
    connect(ui->actionRestart_Phrase, SIGNAL(triggered()), this, SLOT(replayInstructor()));
    connect(ui->actionAbout, SIGNAL(triggered()),this, SLOT(showAboutBox()));
    connect(ui->actionQuiz_Me, SIGNAL(triggered()), this, SLOT(quizMeClicked()));
    connect(ui->actionHome, SIGNAL(triggered()), this, SLOT(showUserScreen()));

    //FFMPEG Process connections
    connect(ffmpeg, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(ffmpegFinished(int,QProcess::ExitStatus)));
    //other connections
    // video finished
    connect(clip, SIGNAL(finished()),this,SLOT(videoFinished()));

    //Connect our timer
    connect(timer, SIGNAL(timeout()), this, SLOT(updateInterval()));

    //and start the timer
    timer->start(1000/frameRate);

    // recent phrase list
    connect(ui->recentPhrasesList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(recentPhraseClicked(QModelIndex)));
}

void MainWindow::createStatusBar()
{
    userLabel = new QLabel("Guest");
    userLabel->setAlignment(Qt::AlignRight);

    statusBar()->addPermanentWidget(userLabel,0);
}

// create menus
void MainWindow::createMenu() {
    ui->menuPractice->addAction(quizMeAction);
}

/* setState
 *  Changes the programs state to the given program state.
 */
void MainWindow::setState(ProgramState newState)
{
    /* TopStack index's (usefull to know whats actually being displayed)
     * 0: PhononWidget
     * 1: Webcam
     * 2: Cartoon
     * 3: NowWhat
     * 4: Rating
     * 5: Quiz1
     * 6: Quzz2
     * 7: Loading
     *
     * BotStack index's
     * 0: PhononWidget
     * 1: Webcam
     * 2: Cartoon
     */



    qDebug() << "Moving from " << state << " to " << newState;

    //Varible declarations, since we cant declare a variable in a switch statement
    QuizDemoWidget* demoWidget;
    QIcon icon; QMovie* loader; QSize uiSize(200,200);
    QPushButton *b;
    QVBoxLayout* suggestedLessonLayout;
    int i = 0;
    QDir test;//creating a qdir object
    QString welcomeText = "Welcome back, ";
    QHBoxLayout* outerLayout;

    /*
     * Clean up after quizes. Usually involves returning
     * the Phonon video widget to the appropriate place.
     */
    //switch video position
    if(state == quizState)
    {
        if (quizWidget) {
            quizWidget->cleanup(); // return video widget to main gui as necessary
            delete quizWidget;
            quizWidget = 0;
        }
        setVideoPosition(MainWindow::TopLeft);
        // restore our state monitor
        connect(clip, SIGNAL(finished()), this, SLOT(videoFinished()));
    }
    else if(state == recordingState)
    {
        ui->webcamLayout2->addWidget(webcam);        
    }
    else if (state == viewingProgressState)
    {
        ui->playDemoButton->setVisible(true);
        ui->stopDemoButton->setVisible(true);
    }
    else if(state == welcomeState || state == userState || state == viewingProgressState)
    {
        ui->phrase->show();
        ui->toolBar->show();
    }

    switch(newState)
    {

    case welcomeState:        

        //set Gesture recognition
        topLeftEnabled = false;
        topRightEnabled = false;

        //set pages
        ui->stackedWidget_top->setCurrentIndex(8);
        ui->stackedWidget_bottom->setCurrentIndex(1);        

        ui->actionQuiz_Me->setEnabled(false);
        ui->phrase->hide();
        ui->toolBar->hide();

        //Set welcome label
        ui->welcomePicture->setClickablePixmap(QPixmap(":images/images/welcome.jpg"));
        break;

    // USER STATE --- CUSTOMISED HOME SCREEN /////////////////////////////////////////
    case userState:
        ui->actionQuiz_Me->setEnabled(true);
        // ensure there is a valid lesson
        if (currentLesson == lessons.end()) {
            currentLesson = lessons.begin();
        }
        // first lesson is default
        withinLesson = true;
        //set Gesture recognition
        topLeftEnabled = false;
        topRightEnabled = false;

        // guest never sees the custom home
        if (currentUser.getName() == "Guest") {
            setState(welcomeState);
            break;
        }
        //set pages
        ui->stackedWidget_top->setCurrentIndex(9);
        ui->stackedWidget_bottom->setCurrentIndex(1);

        //clear phrase label
        ui->phrase->hide();

        //set user name
        ui->userWelcomeLabel->setFont(QFont("serif",12, QFont::Normal));
        ui->userWelcomeLabel->setText(welcomeText.append("<b>" + currentUser.getName() + "</b>").append("!"));

        suggestedLessonLayout = new QVBoxLayout();
        i = 0;
        // add all lessons for now
        foreach (Lesson lesson, lessons) {
            b = new QPushButton(QIcon("icons/"+lesson.getIcon()), lesson.getName(), this);
            //b = new QPushButton
            //connect(b, SIGNAL(clicked()), this, SLOT(lessonSelected()));
            //b = new QPushButton(this);
            //b->addAction(lessonActions.at(i++));
            suggestedLessonLayout->addWidget(b);
            //connect(b, SIGNAL(clicked()), this, SLOT(lessonSelected()));
            // need to find appropriate action from the Lessons menu
            foreach (QAction* action, lessonActions) {
                if (action->text() == lesson.getName()) {
                    connect(b, SIGNAL(clicked()), action, SLOT(trigger()));
                    break;
                }
            }
        }
        i = 0;
        ui->recentPhrasesList->clear();
        foreach (ProgressItem pi, currentUser.getProgress()) {
            // find this phrase object
            //QList<Lesson>::iterator lessonIt = std::find(lessons.begin(), lessons.end(), pi.getLessonName());
            //PhraseCollection::iterator phraseIt = std::find(lessonIt->begin(), lessonIt->end(), pi.getPhraseName());
            PhraseCollection::iterator phraseIt = std::find(phrases.begin(), phrases.end(), pi.getPhraseName());

            //ui->recentPhrasesList->addItem(pi.getPhraseName());
            QString name = phraseIt->getName().append(" (").append(pi.getLessonName()).append(")");
            ui->recentPhrasesList->addItem(new QListWidgetItem(QIcon("icons/"+phraseIt->getIconFilename()),name));

            // add up to 5 recent phrases
            if (++i == 5)
                break;
        }

        outerLayout =new QHBoxLayout();
        outerLayout->addStretch();
        outerLayout->addLayout(suggestedLessonLayout);
        outerLayout->addStretch();
        ui->suggestedLessonsFrame->setLayout(outerLayout);
        break;

    case cartoonState:
        //set Gesture recognition
        topLeftEnabled = true;
        topLeftImage = QImage(":images/images/Play Green.png");
        topRightEnabled = false;

        //set the pages
        ui->stackedWidget_top->setCurrentIndex(2);
        ui->stackedWidget_bottom->setCurrentIndex(1);

        //set the cartoon pic
        ui->cartoon1->setClickablePixmap(image_filename);

        //set the compare option to false
        ui->continueOption->setEnabled(false);
        ui->continueLabel->setEnabled(false);

        break;

    case instructorPausedState:        

        //set Gesture recognition
        topLeftEnabled = true;
        topLeftImage = QImage(":images/images/Play Green.png");
        topRightEnabled = true;
        topRightImage = QImage(":images/images/Stop Green.png");

        //set pages
        ui->stackedWidget_top->setCurrentIndex(0);
        ui->stackedWidget_bottom->setCurrentIndex(1);

        //set pause button to play
        icon.addFile(QString::fromUtf8(":/images/images/Play Green.png"), QSize(), QIcon::Normal, QIcon::Off);
        ui->playDemoButton->setIcon(icon);
        ui->playDemoButton->setToolTip("Play");
        ui->playDemoButton->setText("Play");

        //pause clip
        clip->pause();


        break;

    case instructorPlayingState:
        
        //set Gesture recognition
        topLeftEnabled = true;
        topLeftImage = QImage(":images/images/Pause Green.png");
        topRightEnabled = true;
        topRightImage = QImage(":images/images/Stop Green.png");

        //set pages
        ui->stackedWidget_top->setCurrentIndex(0);
        ui->stackedWidget_bottom->setCurrentIndex(1);

        //Set the video if it we arent coming from the paused state.
        if(state != instructorPausedState)
        {
            setVideo(DemoVideo);
        }
        else
        {
            //Play clip
            clip->play();
        }

        //set play button to pause

        icon.addFile(QString::fromUtf8(":/images/images/Pause Green.png"), QSize(), QIcon::Normal, QIcon::Off);
        ui->playDemoButton->setIcon(icon);
        ui->playDemoButton->setToolTip("Pause");
        ui->playDemoButton->setText("Pause");

        break;

    case nowWhatState:
        //set Gesture recognition
        topLeftEnabled = true;
        topLeftImage = QImage(":images/images/Button-Reload-icon-256.png");
        topRightEnabled = true;
        topRightImage = QImage(":images/images/Button-Record-256x256.png");

        //set pages
        ui->stackedWidget_top->setCurrentIndex(3);
        ui->stackedWidget_bottom->setCurrentIndex(1);

        break;

    case nowWhatAfterRecordingState:
        topLeftEnabled = true;
        topLeftImage = QImage(":images/images/Button-Reload-icon-256.png");
        topRightEnabled = true;
        topRightImage = QImage(":images/images/Button-Next-icon-256.png");
        //set pages
        ui->stackedWidget_top->setCurrentIndex(3);
        ui->stackedWidget_bottom->setCurrentIndex(1);
        ui->continueOption->setEnabled(true);
        ui->continueLabel->setEnabled(true);

        break;


    case recordingState:

        //set Gesture recognition
        topLeftEnabled = false;
        topRightEnabled = true;
        //topRightEnabled = false;
        topRightImage = QImage(":images/images/Stop Blue.png");
        //topRightImage = QImage();

        //move webcam
        ui->webcamLayout1->addWidget(webcam);
        //set pages        
        ui->stackedWidget_top->setCurrentIndex(1);
        ui->stackedWidget_bottom->setCurrentIndex(2);

        //set the cartoon pic
        ui->cartoon2->setClickablePixmap(image_filename);

        //prep the recording vars
        frameCounter = 0;
        #ifdef _WIN32 //windows
            //write multiple picture files together, and then put them together with ffmpeg
        #else //linux
            //=============Create Video file to write 2================
            writer = 0;//ceating an instance of the cvVideoWrite

            test.remove(userVideo_filename);//deleting the previously recorded file

            writer = cvCreateAVIWriter(userVideo_filename.toStdString().c_str(),-1,
                                       25,cvSize(640,480),1);//initializing the writer with the arguments
            //THIS NEEDS TO BE INCORPORATED INTO AN ERROR MESSAGE!!!!!!!!!!!!!!!!!!
            assert(writer);
            //================================================================
        #endif

        break;

    case comparingInstructorPausedState:
        //set Gesture recognition
        topLeftEnabled = false;
        //topLeftImage = QImage(":images/images/Play Green.png");
        topRightEnabled = false;
        //topRightImage = QImage(":images/images/Stop Green.png");

        //set pages
        ui->stackedWidget_top->setCurrentIndex(0);
        ui->stackedWidget_bottom->setCurrentIndex(2);        

        //set pause button to play
        icon.addFile(QString::fromUtf8(":/images/images/Play Green.png"), QSize(), QIcon::Normal, QIcon::Off);
        ui->playDemoButton->setIcon(icon);
        ui->playDemoButton->setToolTip("Play");
        ui->playDemoButton->setText("Play");

        //pause clip
        clip->pause();

        break;

    case comparingInstructorPlayingState:

        //set Gesture recognition
        topLeftEnabled = false;
        //topLeftImage = QImage(":images/images/Pause Green.png");
        topRightEnabled = false;
        //topRightImage = QImage(":images/images/Stop Green.png");

        //set pages
        ui->stackedWidget_top->setCurrentIndex(0);
        ui->stackedWidget_bottom->setCurrentIndex(2);

        //Set the video if it we arent coming from the paused state.
        if(state != comparingInstructorPausedState)
        {
            setVideo(DemoVideo);
        }
        else
        {
            //Play clip
            clip->play();
        }        

        //set play button to pause        
        icon.addFile(QString::fromUtf8(":/images/images/Pause Green.png"), QSize(), QIcon::Normal, QIcon::Off);
        ui->playDemoButton->setIcon(icon);
        ui->playDemoButton->setToolTip("Pause");
        ui->playDemoButton->setText("Pause");

        break;

    case comparingRecordingPausedState:
        //set Gesture recognition
        topLeftEnabled = false;
        //topLeftImage = QImage(":images/images/Play Green.png");
        topRightEnabled = false;
        //topRightImage = QImage(":images/images/Stop Green.png");

        //set pages
        ui->stackedWidget_top->setCurrentIndex(0);
        ui->stackedWidget_bottom->setCurrentIndex(2);

        //set pause button to play
        icon.addFile(QString::fromUtf8(":/images/images/Play Green.png"), QSize(), QIcon::Normal, QIcon::Off);
        ui->playDemoButton->setIcon(icon);

        ui->playDemoButton->setToolTip("Play");
        ui->playDemoButton->setText("Play");

        //pause clip
        clip->pause();

        break;

    case comparingRecordingPlayingState:
        //set Gesture recognition
        topLeftEnabled = false;
        //topLeftImage = QImage(":images/images/Pause Green.png");
        topRightEnabled = false;
        //topRightImage = QImage(":images/images/Stop Green.png");

        //set pages
        ui->stackedWidget_top->setCurrentIndex(0);
        ui->stackedWidget_bottom->setCurrentIndex(2);

        //Set the video if it we arent coming from the paused state.
        if(state != comparingRecordingPausedState)
        {            
            setVideo(UserVideo);
        }
        else
        {
            //Play clip
            clip->play();
        }


        //set play button to pause        
        icon.addFile(QString::fromUtf8(":/images/images/Pause Green.png"), QSize(), QIcon::Normal, QIcon::Off);
        ui->playDemoButton->setIcon(icon);
        ui->playDemoButton->setToolTip("Pause");
        ui->playDemoButton->setText("Pause");

        break;

    case ratingState:
        //set Gesture recognition
        topLeftEnabled = true;
        topLeftImage = QImage(":images/images/unhappy.png");
        topRightEnabled = true;
        topRightImage = QImage(":images/images/happyish.png");

        //set pages
        ui->stackedWidget_top->setCurrentIndex(4);
        ui->stackedWidget_bottom->setCurrentIndex(1);

        //set the cartoon pic
        ui->cartoon2->setClickablePixmap(image_filename);        

        break;

    case quizState:
        // must be in a lesson to have a quiz
        if(/*currentLesson == lessons.end()*/!withinLesson)
        {
            //No more lessons
            setState(welcomeState);
            break;
        }
        else
        {

        QMessageBox::information(this, "Quiz", "Get ready for a quiz!", QMessageBox::Ok);

        //set pages
        ui->stackedWidget_top->setCurrentIndex(5);
        // QuizWidget has phonon player on bottom.
        //ui->stackedWidget_bottom->setCurrentIndex(0);
        // QuizDemoWidget has webcam on bottom
        // needs to be tested w/ webcam
        ui->stackedWidget_bottom->setCurrentIndex(1);

        //set Gesture recognition
        topLeftEnabled = false;
        topRightEnabled = false;

        // create sample question

        // no 'clear' method for widget.
        // remove and delete old quiz
        if (quizWidget != 0) {
            ui->quizLayout->removeWidget(quizWidget);
            delete quizWidget;
        }

        // create fresh quiz and add
        //quizWidget = new QuizWidget();
        demoWidget = new QuizDemoWidget();
        quizWidget = demoWidget;
        // pass the phonon widget to the quiz widget.
        // it will be returned to the top when done.
        demoWidget->setPhononWidget(ui->phononWidget1, ui->topPhononFrame->layout(), clip);
        QImage iconImage;
        iconImage.load("icons/"+currentLesson->getIcon());
        qDebug() << "lesson icon: " << currentLesson->getIcon();
        demoWidget->setImage(iconImage);
        ui->quizLayout->addWidget(quizWidget);
        // wire up the quiz
        connect(quizWidget, SIGNAL(done()), this, SLOT(quizDone()));
        // disconnect 'video finished'
        disconnect(clip, SIGNAL(finished()), this, SLOT(videoFinished()));

        // add questions to quiz
        if (!lessons.empty())
        {
            Lesson lesson = *currentLesson;//  lessons[0];

            QList<Phrase> options;
            for (PhraseCollection::iterator it = lesson.begin(); it != lesson.end(); ++it)
            {
                options.append((*it));

                if ((++i) == 4)
                {
                    break;
                }
            }
            //qDebug() << "Answer should be: " << options[0];
            // set question. first option is answer
            quizWidget->setQuestion(options, options[0]);

            // begin option video playback
            demoWidget->playOptions();

            break;

            /*
             * Quiz video
             */
            clip->clear();

            // move phonon widget to bottom.
            setVideoPosition(MainWindow::BottomRight);

            // get Windows Media Player audio hardware error if we listen for
            // state changes at this point


            // load up demo video
            setDemoVideoFilename(options[0].getVideoFilename());
            setVideo(MainWindow::DemoVideo);

            }
        }
        break;

     case loadingState_recording:
     case loadingState:
        //set Gesture recognition
        topLeftEnabled = false;
        topRightEnabled = false;

         //set pages
         ui->stackedWidget_top->setCurrentIndex(7);
         ui->stackedWidget_bottom->setCurrentIndex(2);

         //set the cartoon pic
         ui->cartoon2->setClickablePixmap(image_filename);

         //put up loading pictures
         loader = new QMovie(":images/images/loader.gif");

         loader->setScaledSize(uiSize);
         ui->loadingAnimation->setMovie(loader);
         ui->loadingAnimation->setScaledContents(false);
         loader->start();
         break;

     case viewingProgressState:

         //set Gesture recognition
         topLeftEnabled = false;
         topRightEnabled = false;

         ui->stackedWidget_top->setCurrentIndex(0);
         ui->stackedWidget_bottom->setCurrentIndex(2);


         ui->playDemoButton->setVisible(false);
         ui->stopDemoButton->setVisible(false);
         ui->phrase->hide();

         ui->cartoon2->setClickablePixmap(QPixmap(""));
         break;

    }

    //set state variable
    state = newState;
}

//__________________________________________________________Main Slots______________________________________________________________________________

/* Play Slot
 * This slot is called whenever the play button is clicked
 * It first checks if there is something that could be played and give an appropriate error message if not.
 * If the play1Button is currently a 'play' icon, the video will start playing and the icon will change to a pause icon.
 * The tooltip will also change according. If the button is set to a 'pause' icon, this slot will pause the video,
 * change the tooltip and return the icon 'play'.
 */
void MainWindow::play()
{

    //Rewrite using states
    switch(state)
    {
    case cartoonState:
        setState(instructorPlayingState);
        break;

    case instructorPlayingState:
        setState(instructorPausedState);
        break;

    case instructorPausedState:
        setState(instructorPlayingState);
        break;

    case nowWhatState:
        setState(comparingInstructorPlayingState);
        break;

    case comparingInstructorPausedState:
        setState(comparingInstructorPlayingState);
        break;

    case comparingInstructorPlayingState:
        setState(comparingInstructorPausedState);
        break;

    case comparingRecordingPausedState:
        setState(comparingRecordingPlayingState);
        break;

    case comparingRecordingPlayingState:
        setState(comparingRecordingPausedState);
        break;
    default:
        //qDebug() << "Invalid state!" << endl;
        break;
    }
}

void MainWindow::replayInstructor()
{
    setState(instructorPlayingState);
}

/*Stop slot
 * This slot is called whenever a stop button is pressed.
 * It will either stop playback of phonon video
 * or it will stop recording and proceed as needed
 */
void MainWindow::stop()
{
    QStringList args;
    QString program("\"");
    long time;
    int fps;

    switch(state)
    {
    case instructorPausedState:
    case instructorPlayingState:
        clip->stop();
        setState(nowWhatState);
        break;

    case recordingState:
        #ifdef _WIN32 //windows

        buildingVideo = true;

        program.append(QDir::toNativeSeparators(dir));
        program.append("\\ffmpeg\"");

        //Work out the users actual frame rate while recording - this makes sure the playback is at the same speed.
        time = videoTimer.elapsed()/1000;
        if(time == 0)
        {
            time = 1;
        }
        fps = frameCounter/time;
        //Dont delete this debug statement - its fun to check what framerates we get!
        //qDebug() << "Setting encode rate to " << fps <<"fps.";

        args << "-r" << QString::number(fps) << "-i"
                << QString("temp\\frame_%01d").append(frameExtension) << "-an" << "-sameq" << "-y" << "Temp_Video.wmv";        
        ffmpeg->setStandardErrorFile("ffmpeg_output.txt");
        ffmpeg->start(program, args);


        #else //linux
        cvReleaseVideoWriter(&writer);//releasing the video writer
        #endif
        setState(nowWhatAfterRecordingState);
        break;

    case comparingInstructorPausedState:
    case comparingInstructorPlayingState:

        clip->stop();
        //if the video has not yet been assembled
        if(buildingVideo)
        {
            setState(loadingState);
        }
        else
        {
            setState(comparingRecordingPlayingState);
        }

        break;

    case comparingRecordingPlayingState:
    case comparingRecordingPausedState:
        clip->stop();
        setState(ratingState);
        break;
    default:
        qDebug() << "Unknown state in stop method: " << state;
        break;
    }
}

/* VideoFinished slot
 * This slot is called when the video has finished being played.
 */
void MainWindow::videoFinished()
{
    qDebug() << "Video finished, state: " << state << endl;
    // do nothing in quiz mode
    if (state == quizState)
    {
        // replay clip
        clip->stop();
        clip->play();
    }
    else
    {
        stop();
    }
}

/* Record Slot
 * This slot will record the live video feed from the webcam and
 * save it as a video clip to be played back later. It will record
 * for a maximum of 20 seconds.
 */
void MainWindow::record()
{
    //stop the clip if its playing
    clip->stop();
    clearTempDir();
    //add protection, so that we cant record a new vid while ffmpeg is still busy
    if(!buildingVideo)
    {
        setState(recordingState);
    }
    else
    {
        setState(loadingState_recording);
    }
    ui->actionCompare_my_video->setEnabled(true);

}

/* Comparing Slot
 * This slot is used when comparing the user attempt and the demo
 * one after each other.
 */
void MainWindow::comparing()
{
    setState(comparingInstructorPlayingState);
}

/*Process finished slot
 * Gets called once ffmpeg has completed
 */
void MainWindow::ffmpegFinished(int exitCode, QProcess::ExitStatus exitStatus)
{

    qDebug() << "FFmpeg done: Exit code = " << exitCode <<". Exit status = " << exitStatus;


    //now delete all the consruction frames
    clearTempDir();

    buildingVideo = false;

    if(state == loadingState)
    {
        setState(comparingRecordingPlayingState);
    }
    else if(state == loadingState_recording)
    {
        setState(recordingState);
    }

}

/* StackClicked slot
 * This slot is called when the stack widget is clicked
 * it plays or pauses the current video as needed if displaying video
 */
void MainWindow::topStackClicked()
{
    if(ui->stackedWidget_top->currentIndex()==0) //if its showing video
    {
        play();//or pause
    }
    else if(state == recordingState)
    {
        stop();//stop recording
    }
}

// ??
void MainWindow::openLesson()
{
    QFileDialog dia(this);
    dia.setFileMode(QFileDialog::ExistingFile);
    dia.setNameFilter(tr("Lessons (*.xml)"));
    if (dia.exec())
    {
        QStringList lessonfilelist = dia.selectedFiles();
        QString lessonfile = lessonfilelist.at(0);
        Lesson l; l.fromXML(lessonfile);

        if (lessons.contains(l))
            lessons.removeOne(l);
        lessons.append(l);
        QDir dir(lessonfile);
        dir.cdUp(); dir.cdUp();

        QFile icon(dir.absolutePath()+QString("icons/")+l.getIcon());
        icon.copy(QDir::currentPath()+"icons/"+l.getIcon());
        foreach (Phrase p, l)
        {
            QFile vid(dir.absolutePath()+QString("videos/")+p.getVideoFilename());
            vid.copy(QDir::currentPath()+"videos/"+p.getVideoFilename());
            QFile car(dir.absolutePath()+QString("cartoons/")+p.getCartoonFilename());
            car.copy(QDir::currentPath()+"cartoons/"+p.getCartoonFilename());
            QFile ico(dir.absolutePath()+QString("icons/")+p.getIconFilename());
            ico.copy(QDir::currentPath()+"icons/"+p.getIconFilename());
        }

        l.toXML(tr("lessons/")+l.getName());

        QAction* newLesson = new QAction(l.getName(), this);
        // path to lesson icon is relative to root for flexibility
        newLesson->setIcon(QIcon(QString("icons/").append(l.getIcon())));
        connect(newLesson, SIGNAL(triggered()), this, SLOT(lessonSelected()));
        ui->menuLesson->addAction(newLesson);
        newLesson->setStatusTip(l.getDescription());
    }
}

//_____________________________________________________________QUIZ section_______________________________________________________________________
// 'quiz me' event handler
void MainWindow::quizMeClicked()
{
    setState(quizState);
}

// correct quiz answer
void MainWindow::quizCorrect() {    
    return;
}

// wrong quiz answer
void MainWindow::quizWrong() {
    return;
}

// clean up after quiz
void MainWindow::quizCleanup() {
    // return phonon widget to top location
    clip->stop();    
}

void MainWindow::quizDone()
{
    setState(userState);
    //******************************************if lesson is still busy should go back to next phrase*******************************
}

//____________________________________________________________Settings stuff________________________________________________________________________

void MainWindow::videoQualityChanged(int val)
{    
    vidQuality = val;
    saveSettings();
}

void MainWindow::videoFrameRateChanged(int val)
{    
    frameRate = val;
    timer->setInterval(1000/frameRate);
    saveSettings();
}

void MainWindow::videoFrameFormatChanged(QString extension)
{    
    frameExtension = extension;
    saveSettings();
}

void MainWindow::maxRecordingLengthChanged(int val)
{    
    maxTime = val;
    saveSettings();
}

void MainWindow::gesturesEnabledChanged(bool enabled)
{
    gesturesEnabled = enabled;
    saveSettings();
}

void MainWindow::sensitivityChanged(double sensitivity)
{
    gestureTopLeft->setSensitivity(sensitivity);
    gestureTopRight->setSensitivity(sensitivity);
    saveSettings();
}

void MainWindow::preferencesClosed(int code)
{    
    qDebug() << code;
    uip.listWidget->setCurrentRow(0);
    uip.stackedWidget->setCurrentIndex(3);
}

void MainWindow::setVideo(MainWindow::VideoSources src)
{

    QFile vid;
    bool error = false;
    Phonon::MediaSource *mediaSource;
    clip->clear();

    switch (src) {
    case MainWindow::DemoVideo:
        // load the demo video
        vid.setFileName(demoVideo_filename);
        if(vid.exists())
        {
            mediaSource = new Phonon::MediaSource(demoVideo_filename);
        }
        else
        {
            error = true;
        }
        break;
    case MainWindow::UserVideo:
        // load user video
        vid.setFileName(userVideo_filename);
        if(vid.exists())
        {
            mediaSource = new Phonon::MediaSource(userVideo_filename);
        }
        else
        {
            error = true;
        }
    }

    if(!error)
    {
        mediaSource->setAutoDelete(true); // gc picks it up
        clip->setCurrentSource(*mediaSource);
        // wire us up to be notified when video is done loading.
        // the slot will disconnect this when loading is done!
        connect(clip, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(phononStateChanged(Phonon::State,Phonon::State)));
    }else
    {
        //Error checking========================================
        QMessageBox msgBox;
        msgBox.setText("Could not play video file!");
        msgBox.setInformativeText("Would you like to learn another phrase instead?");
        msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.setIcon(QMessageBox::Warning);
        QDir dir;
        QString detail = "Could not open '" + dir.absoluteFilePath(demoVideo_filename) + "'";
        msgBox.setDetailedText(detail);
        int ret  = msgBox.exec();

        switch(ret)
        {
                case QMessageBox::No:
            //do nothing....
                showCartoon();
            break;
                case QMessageBox::Yes:
            //open search dialog
            find();
            break;
                case QMessageBox::Cancel:
            //do nothing - makes user feel happy to have a cancel key
            break;
        }
        //End Error checking====================================
    }
}

void MainWindow::setCartoonFilename(const QString& f)
{
    image_filename = dir + "/cartoons/" + f;
}

// mutator: demo video filename
void MainWindow::setDemoVideoFilename(const QString& f) {
    demoVideo_filename = "videos/" + f;
}

void MainWindow::clearTempDir()
{
    QDir directory(QDir::current());
    QDir tempDir(directory.path()+"/temp");
    QStringList fileList = tempDir.entryList();
    for(int i = 0; i < fileList.size();i++)
    {
        tempDir.remove(fileList.at(i));
    }

}

//changes the view from being horizontal to vertical and visa versa
void MainWindow::changeView()
{
    if(ui->splitter->orientation()==Qt::Horizontal)
    {
        ui->splitter->setOrientation(Qt::Vertical);
    }
    else
    {
        ui->splitter->setOrientation(Qt::Horizontal);
    }
    saveSettings();
}

//__________________________________________________________Showing the right states__________________________________________________________________

//shows the about dialog
void MainWindow::showAboutBox()
{
    aboutBox.show();
}

/* ShowCartoon slot
 * This slot is called when the view is changed from anything else to displaying just the cartoon
 * on the top widget and the webcam on the bottom
 */
void MainWindow::showCartoon()
{
    setState(cartoonState);
}

void MainWindow::showUserScreen()
{
    setState(userState);
}

/* ShowHowDidIDo slot
 * This slot is called to display the correct combinations of widgets
 * for the user to rate their attempt of the current clip
 */
void MainWindow::showHowDidIDo()
{
    setState(ratingState);
}

void MainWindow::showPreferences()
{
    preferenceWindow.show();
    uip.stackedWidget->setCurrentIndex(0);
    //uip.listWidget->setItemSelected(uip.listWidget->item(0),1);
}

void MainWindow::userAccountClicked()
{
    saveUsers();
    userCollection.clear();
    userCollection.load("users.xml");

    QUsersDialog *usersDialog = new QUsersDialog();
    usersDialog->setModal(true);
    usersDialog->setUserCollection(&userCollection);
    usersDialog->show();

    connect(usersDialog, SIGNAL(userCollectionChanged()), this, SLOT(saveUsers()));
    connect(usersDialog, SIGNAL(signIn(QString)), this, SLOT(signInUser(QString)));
}

//___________________________________________________Lessons, ratings and moving between phrases__________________________________________________

// One of the Lesson actions has been clicked
void MainWindow::lessonSelected()
{
    // find the lesson name
    QAction* src = qobject_cast<QAction*>(sender());

    // find the lesson corresponding to this action
    currentLesson = std::find(lessons.begin(), lessons.end(), src->text());

    if (currentLesson->size() == 0)
    {
        QErrorMessage errorM(this);
        errorM.setModal(true);
        errorM.showMessage("The selected Lesson is empty.");
        errorM.exec();
        return;
    }

    int max = 0;
    for (int i = 0; i < currentUser.getProgress().size(); i++)
    {
        if (!currentLesson->contains(Phrase(currentUser.getProgress().at(i).getPhraseName())))
            continue;

        if (currentLesson->at(
                currentLesson->indexOf(
                        Phrase(currentUser.getProgress().at(i).getPhraseName())
                        )).getSequence() > max)

            max = currentLesson->at(
                    currentLesson->indexOf(
                            Phrase(currentUser.getProgress().at(i).getPhraseName())
                            )).getSequence();
    }
    //qDebug() << "loop done, max =" << max;

    //if (max > 0) currentLesson->shuffle(max);
    //else currentLesson->shuffle();

    // reset current lesson
    currentPhrase = currentLesson->begin();

    // choose first phrase from this lesson
    Phrase phrase = currentLesson->at(0);

    // we are within lesson
    withinLesson = true;

    // present them
    presentPhrase(phrase);

    ui->actionSee_cartoon->setEnabled(true);
    ui->actionPlay_demo_video->setEnabled(true);
    ui->actionRecord_me->setEnabled(true);
    ui->playCartoonButton->setEnabled(true);
    ui->actionCompare_my_video->setEnabled(false);
    ui->actionSkip_Phrase->setEnabled(true);
    ui->actionPrevious_Phrase->setEnabled(false);
    ui->actionRestart_Phrase->setEnabled(true);
    ui->actionQuiz_Me->setEnabled(true);

    //show toolbar
    ui->toolBar->show();
}

/* Rating Happy slot
 * This slot stores the user as happy with their attempt
 * Their video is saved and stored as required
 * And they move on to the next phrase
 */
void MainWindow::rating_happy()
{
    currentProgress.setStatus(ProgressItem::Learnt);
    saveUserProgress();    
    presentNextPhrase();
}

/* Rating Ok slot
 * This slot will be used to store their video attempt
 * But add the phrase back in to the lesson for review at a later stage
 */
void MainWindow::rating_ok()
{
    currentProgress.setStatus(ProgressItem::Revisit);
    saveUserProgress();    
    presentNextPhrase();
    currentLesson->append(*currentPhrase);
}

/* Rating Sad slot
 * This slot is called when the user is not happy with their attempt
 * It returns them to being able to record, watch demo etc
 */
void MainWindow::rating_sad()
{
    currentProgress.setStatus(ProgressItem::TryAgain);
    saveUserProgress();    
    setState(nowWhatState);
}

// show the next phrase in the current lesson
bool MainWindow::presentNextPhrase()
{
    //Clear Temp dir
    clearTempDir();
    // make sure we're in a valid lesson state
    /*if (!withinLesson)
    {
        return false;
    }*/
    if(!withinLesson/*currentLesson == lessons.end()*/)
    {
        setState(userState);
        return false;
    }
    // move to next phrase
    ++currentPhrase;
    if (currentPhrase == currentLesson->end())
    {
        // lesson is OVER
        QMessageBox::information(this, "Lesson complete!", "You've finished the " + currentLesson->getName() + " lesson.");
        withinLesson = false;

        setState(quizState);
        return true; // lesson over
    }
    else
    {
        Phrase p = *currentPhrase;
        presentPhrase(p);

        ui->actionCompare_my_video->setEnabled(false);
        ui->actionPlay_demo_video->setEnabled(true);
        ui->actionRecord_me->setEnabled(true);
        ui->actionRestart_Phrase->setEnabled(true);
        ui->actionSee_cartoon->setEnabled(true);
        ui->actionPrevious_Phrase->setEnabled(true);

        return false; // lesson continues
    }


}

// present an arbitary phrase to the user
void MainWindow::presentPhrase(Phrase& phrase) {
    // set current video to phrase video
    setDemoVideoFilename(phrase.getVideoFilename());
    // set current cartoon to phrase cartoon
    setCartoonFilename(phrase.getCartoonFilename());
    //clip->setCurrentSource(Phonon::MediaSource(demoVideo_filename));
    setVideo(MainWindow::DemoVideo);
    // show cartoon and phrase
    setState(cartoonState);
    ui->phrase->setText(phrase.getName());
    phraseStartTime = QTime::currentTime();
    currentProgress = ProgressItem();

    ui->replayOption->setEnabled(true);
}

//skips the user to the next phrase in the lesson without saving current progress
void MainWindow::skipPhrase()
{
    QMessageBox msgBox;
    msgBox.setText("Skipping phrase");
    msgBox.setInformativeText("Are you sure you want to skip this phrase? You will be able to do it again later.");
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
    msgBox.setDefaultButton(QMessageBox::Yes);
    msgBox.setIcon(QMessageBox::Question);
    int ret = msgBox.exec();
    if(ret == QMessageBox::Yes)
    {
        currentLesson->append(*currentPhrase);
        presentNextPhrase();
    }
    else
    {
        //do nothing, leave the program in its current state
        return;
    }
}

//returns the user to the phrase they were working on before and lets them try again
bool MainWindow::previousPhrase()
{
    QMessageBox msgBox;
    msgBox.setText("Going back to previous phrase");
    msgBox.setInformativeText("Are you sure you want to go back to the last phrase? You will lose anything you've done on this phrase so far.");
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
    msgBox.setDefaultButton(QMessageBox::Yes);
    msgBox.setIcon(QMessageBox::Question);
    int ret = msgBox.exec();
    if(ret == QMessageBox::Yes)
    {
        //Clear Temp dir
        clearTempDir();
        // make sure we're in a valid lesson state
        if (!withinLesson)
        {
            return false;
        }

        // move to previous phrase
        --currentPhrase;

        Phrase p = *currentPhrase;
        presentPhrase(p);

        ui->actionCompare_my_video->setEnabled(false);
        ui->actionPlay_demo_video->setEnabled(true);
        ui->actionRecord_me->setEnabled(true);
        ui->actionRestart_Phrase->setEnabled(true);
        ui->actionSee_cartoon->setEnabled(true);

        if(currentPhrase == currentLesson->begin())
        {
            ui->actionPrevious_Phrase->setEnabled(false);
        }

        return true;//lesson continues

    }
    else
    {
        //do nothing, leave the program in its current state
        return false;
    }


}


//____________________________________________________________________Search window__________________________________________________________________

/* okClicked slot --- search engine related
 * This slot is called when the ok button in the search window is pressed, indicating that the user want to open a database item
 * This slot then updates the main GUI to reflect the search word in the lineEdit and loads the appropriate video and image.
 * It also hides the search window and enables the main gui.
 */
void MainWindow::okClicked()
{

    if(searchEngine.listWidget->selectedItems().size()==1)//if there is something selected
    {
        // find() is used twice.
        // first to retrieve all synonyms
        // second to retrieve Phrase corresponding to selected item from list widget
        QList<Phrase*> selected = searchEngine.find(searchEngine.listWidget->selectedItems().front()->text());

        //change main gui text in phrase lable to the chosen word on all pages
        // update ALL widgets
        //ui->phrase->setText(selected.front()->getName());

        withinLesson = false;

        currentLesson = lessons.end();
        // find the lesson which corresponds to this phrase
        for (QList<Lesson>::iterator it = lessons.begin(); it != lessons.end(); ++it) {
            if (it->contains(*selected.front())) {
                currentLesson = it;
                break;
            }
        }
        if (currentLesson == lessons.end()) {
            // this phrase does not belong to any lesson
            currentLesson = 0; // crash
            qDebug() << "Could not enter thesaurus phrase into progress report because it was not associated with any lesson" << endl;
        }

        // set demonstrator video to selected phrase
        setDemoVideoFilename(selected.front()->getVideoFilename());
        // set cartoon to selected cartoon
        setCartoonFilename(selected.front()->getCartoonFilename());

        presentPhrase(*selected.front());
        //setState(cartoonState);
    }
    //else ignore search and leave everything as it was --> basically works as a cancel option
    searchEngine.hide();//close the search window
}

/* Find slot
 * This slot is called when the user clicks on the search icon.
 * It will stop any video playback and open the search window
 * where the search results will be displayed.
 */
void MainWindow::find()
{
    // bind thesaurus to search dialog
    searchEngine.setThesaurus(&thesaurus);
    searchEngine.show();
    searchEngine.lineEdit->setText(ui->searchLineEdit->text());
}

//_______________________________________________________User stuff and progress related methods_______________________________________________________

void MainWindow::saveUsers()
{
    userCollection.save("users.xml");
}

void MainWindow::saveUserProgress()
{
    if (currentUser.getName() == "Guest")
        return;
    currentProgress.setLessonName((*currentLesson).getName());
    currentProgress.setPhraseName((*currentPhrase).getName());
    currentProgress.setVideoFilename(userVideo_filename, currentUser.getName());
    currentProgress.setDuration(phraseStartTime.msecsTo(QTime::currentTime()));
    currentUser.addProgressItem(currentProgress);
    userCollection.replace(userCollection.indexOf(currentUser), currentUser);
    saveUsers();
}

void MainWindow::openProgressViewerFiltered()
{
    setState(viewingProgressState);
    ProgressViewer pv(this);
    pv.filter(currentUser.getName());
    pv.exec();
    setState(userState);
}

void MainWindow::openProgressViewer()
{
    setState(viewingProgressState);
    ProgressViewer pv(this);
    pv.exec();
    setState(userState);
}

//PLEASE ADD A COMMENT TO THIS! I HAVE NO IDEA WHERE IT IS USED AND WHY! :) thanks! (caps was only so that someone would actually read this and change it ;)
void MainWindow::playVideo(QTreeWidgetItem *it, int col)
{
    clip->setCurrentSource(Phonon::MediaSource(it->data(5, Qt::UserRole).toString()));
    clip->play(); col;
    ui->cartoon2->setClickablePixmap(QPixmap(QString("cartoons/")+it->text(3)+QString(".jpg")));
}

void MainWindow::signInUser(QString name)
{
    userLabel->setText(name);
    userCollection.clear();
    userCollection.load("users.xml");
    if (userCollection.contains(User(name)))
    {
        currentUser = userCollection[userCollection.indexOf(User(name))];
    }
    else
    {
        currentUser = User(name);
        userCollection.append(currentUser);
    }

    loadSettings();
    if(name == "Guest")
    {
       setState(welcomeState);
    }
    else
    {
        QMessageBox::information(this, "Switch user", "You are now signed in as '" + name +"'.");
        setState(userState);
    }


}

void MainWindow::loadSettings()
{
    mainSettings.beginGroup(currentUser.getName());
        if (mainSettings.value("verticalGUI", QVariant(true)).toBool())
            ui->splitter->setOrientation(Qt::Vertical);
        else ui->splitter->setOrientation(Qt::Horizontal);
        vidQuality = mainSettings.value("vidQuality", QVariant(50)).toInt();
        frameRate = mainSettings.value("frameRate", QVariant(25)).toInt();
        maxTime = mainSettings.value("maxTime", QVariant(15)).toInt();
        frameExtension = mainSettings.value("frameExtension", QVariant(".jpg")).toString();
        gestureTopLeft->setSensitivity(mainSettings.value("sensitivity",2.0f).toDouble());
        gestureTopRight->setSensitivity(mainSettings.value("sensitivity",2.0f).toDouble());
        gesturesEnabled = mainSettings.value("gesturesEnabled", QVariant(true)).toBool();
    mainSettings.endGroup();

    uip.showHorizontally->setChecked(ui->splitter->orientation() == Qt::Horizontal);
    uip.recordingLengthBox->setValue(maxTime);
    uip.qualitySlider->setValue(vidQuality);
    uip.formatBox->setCurrentIndex(uip.formatBox->findText(frameExtension));
    uip.frameRateBox->setValue(frameRate);
    uip.gestureRecognitionCheckBox->setChecked(gesturesEnabled);
    uip.sensitivitySpinBox->setValue(gestureTopLeft->getSensitivity());

}

void MainWindow::saveSettings()
{
    mainSettings.beginGroup(currentUser.getName());
        if (ui->splitter->orientation() == Qt::Vertical)
            mainSettings.setValue("verticalGUI", QVariant(true));
        else mainSettings.setValue("verticalGUI", QVariant(false));
        mainSettings.setValue("vidQuality", QVariant(vidQuality));
        mainSettings.setValue("frameRate", QVariant(frameRate));
        mainSettings.setValue("maxTime", QVariant(maxTime));
        mainSettings.setValue("frameExtension", QVariant(frameExtension));
        mainSettings.setValue("gesturesEnabled", QVariant(gesturesEnabled));
        mainSettings.setValue("sensitivity", QVariant(gestureTopLeft->getSensitivity()));
    mainSettings.endGroup();
}

//___________________________________________________________________Lower level stuff__________________________________________________________________
/**
 * Monitors Phonon's state for errors.
 * @param newState clip's current state
 * @param oldState not used
 */
void MainWindow::phononStateChanged(const Phonon::State newState, const Phonon::State oldState) {
    if (/*Phonon::ErrorState == newState*/false)
    {
        // error occurred
        QString msg = "An error occurred with video playback:\n";
        msg += "Error type: ";
        msg += QString::number(clip->errorType()).append(": ");
        // show msg for error type
        switch (newState) {
        case Phonon::NoError:
            msg += "No error";
            break;
        case Phonon::NormalError:
            msg += "Normal error (operation can continue)";
            break;
        case Phonon::FatalError:
            msg += "Fatal error. Program will end now.";
            break;
        default:
            break;
        }

        msg += "\n";
        msg += clip->errorString();
        msg += "\nDemo video was: ";
        msg += demoVideo_filename;
        msg += "\nUser video was: ";
        msg += userVideo_filename;
        if (clip != 0) {
            QMessageBox::warning(this, "Phonon error", msg, QMessageBox::Abort);
        }
    }

    // start playing video once done loading.
    // i.e. invoke play() when old state is Loading
    if (Phonon::LoadingState == oldState)
    {
        // stop listening for state changes
        disconnect(this, SLOT(phononStateChanged(Phonon::State,Phonon::State)));
        //play();
        clip->play();
    }
}

// reparent the phonon widget
bool MainWindow::setVideoPosition(const MainWindow::VideoPositions &pos) {
    // phonon widget needs to be directly within stacked widget
    // for automatic resizing to work correctly.
    // i.e. no intermediate container
    switch (pos) {
    case MainWindow::TopLeft:
        if (ui->topPhononFrame ==  ui->phononWidget1->parent()) {
            // widget already there
            return false;
        } else {
            //QVBoxLayout *layout = new QVBoxLayout(this);
            //layout->addWidget(ui->phononWidget1);
            //ui->topPage1->setLayout(layout);

            // move widget to top
            // note how the widget's layout is used
            ui->topPhononFrame->layout()->addWidget(ui->phononWidget1);
            return true;
        }
    case MainWindow::BottomRight:
        if (ui->bottomPhonon ==  ui->phononWidget1->parent()) {
            // widget already there
            return false;
        } else {
            // move widget to bottom
            ui->bottomPhonon->addWidget(ui->phononWidget1);
            return true;
        }
    default:
        return false;
    }
}

void MainWindow::gestureDetected(int id)
{
    if(id == 0)
    {
        switch(state)
        {
        case cartoonState:
            play();
            break;
        case instructorPausedState:
        case instructorPlayingState:
            play();
            break;
        case nowWhatState:
        case nowWhatAfterRecordingState:
            replayInstructor();
            break;
        case comparingInstructorPausedState:
        case comparingInstructorPlayingState:
        case comparingRecordingPausedState:
        case comparingRecordingPlayingState:
            play();
            break;
        case ratingState:
            rating_sad();
            break;
        default:
            qDebug() << "Reached invalid case in left gesture recogniser. State was "<< state;
            break;
        }
    }
    else if (id = 1)
    {
        switch(state)
        {
        case recordingState:
            stop();
            break;
        case instructorPausedState:
        case instructorPlayingState:
            stop();
            break;
        case nowWhatState:
            record();
            break;
        case nowWhatAfterRecordingState:
            comparing();
            break;
        case comparingInstructorPausedState:
        case comparingInstructorPlayingState:
        case comparingRecordingPausedState:
        case comparingRecordingPlayingState:
            stop();
            break;
        case ratingState:
            rating_happy();
            break;
        default:
            qDebug() << "Reached invalid case in left gesture recogniser. State was "<< state;
            break;
        }
    }
    else
    {
        qDebug() << "Gesture received from unknown source: " <<id;
    }
}

/* UpdateInterval Method
 * This is what code is executed every time the timer ticks. The
 * timer generally ticks 30 times a second, defined by the creation of
 * the timer in the play2() method. The code here gets the height of
 * the tabwindow, then gets a frame from the web cam and then draws
 * that frame to the tab scaled to the correct size (maintaining aspect
 * ratio). The timer slows down when playing back a recording and then speeds
 * back up in webcam mode.
 */
void MainWindow::updateInterval()
{

    //rendering and resizing of webcam window
    //vertical size
    if(ui->stackedWidget_bottom->currentIndex() == 1)//webcam at bottom
    {
        hSize = ui->frame2->height();
    }
    else//webcam at top
    {
        hSize = ui->frame->height();
    }
    
    //horizontal size
    if(ui->stackedWidget_bottom->currentIndex() == 1)//webcam at bottom
    {
        wSize = ui->frame2->width();
    }
    else//webcam at top
    {
        wSize = ui->frame->width();
    }


    if(hasCamera)
    {
        IplImage *image=cvQueryFrame(camera);
        cvFlip(image, NULL ,1);
        //pass frame on to our vid widget
        webcam->putImage(image);

        //Error checking========================================
        if(image == NULL)
        {
            QMessageBox msgBox;
            msgBox.setText("Failed to retrieve a video frame from camera!");
            msgBox.setInformativeText("See details for more information.");
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.setDefaultButton(QMessageBox::Ok);
            msgBox.setIcon(QMessageBox::Critical);
            QString detail = "The program could not retrieve any video frames from the systems "
                             "webcam. This could be caused by a faulty or intermittant webcamera. "
                             "Make sure that your webcam is plugged in and properly functional and "
                             "then try to restart the program again.";
            msgBox.setDetailedText(detail);
            msgBox.exec();
            //run assertion which will close the program in an error code, specifying where the error occured.
            assert(image);
        }
        //End Error checking====================================
        if(state == recordingState)
        {
            if(frameCounter == 0)
            {
                videoTimer.start();
            }
            frameCounter++;
            //convert from milis to seconds
            if(videoTimer.elapsed()/1000 <= maxTime)
            {
                #ifdef _WIN32 //windows - write a slideshow to file, and then merge them (cv freezes pc)
                QImage frame = webcam->convertToQImage(image);
                QString frameName("temp\\frame_");
                frameName.append(QString::number(frameCounter));
                frameName.append(frameExtension);
                frame.save(frameName, 0 , vidQuality);


                #else //linux - use cv's write to file method
                    cvWriteFrame(writer,image);      // add the frame to the file
                    cvWriteFrame(writer,image);      // add the frame to the file             dd
                #endif
                //every 20 frames turn the red square on and off
                if(frameCounter%10 == 0)
                {
                    if(flashRecordingSquare)
                    {
                        flashRecordingSquare = false;
                    }
                    else
                    {
                        flashRecordingSquare = true;
                    }
                }
                if(flashRecordingSquare)
                {
                    webcam->paintWriting("Recording", QRect(120, 400, 400, 60));
                }
            }
            else
            {
                stop();
            }
        }


        //if we are running gesture recognition
        if(gesturesEnabled)
        {
            if(topLeftEnabled)
            {
                gestureTopLeft->nextFrame(image);
                gestureTopLeft->checkForGesture();

                int x = gestureTopLeft->getX();
                int y = gestureTopLeft->getY();

                QRect position(x, y, gestureTopLeft->getWidth(), gestureTopLeft->getHeight());
                webcam->paintSubImage(&topLeftImage, position);
            }

            if(topRightEnabled)
            {
                gestureTopRight->nextFrame(image);
                gestureTopRight->checkForGesture();

                int x = gestureTopRight->getX();
                int y = gestureTopRight->getY();

                QRect position(x, y, gestureTopRight->getWidth(), gestureTopRight->getHeight());
                webcam->paintSubImage(&topRightImage, position);
            }
        }


        //finally draw to screen
        if((hSize*4)<(wSize*3))
        {
            webcam->paintLabel(hSize, true);
        }
        else
        {
            webcam->paintLabel(wSize, false);
        }

    }//end webcam loop
}

void MainWindow::recentPhraseClicked(QModelIndex index) {
    // get phrase name from list item. remove (lesson) which is appended
    QString name = ui->recentPhrasesList->selectedItems().front()->text().replace(QRegExp(" (.*)$"), "");
    PhraseCollection::iterator p = std::find(phrases.begin(), phrases.end(), name);
    qDebug() << name;

    // copied from okClicked()

    //change main gui text in phrase lable to the chosen word on all pages
    // update ALL widgets
    //ui->phrase->setText(selected.front()->getName());

    withinLesson = true;

    currentLesson = lessons.end();

    /*
     * Note: sequence control may have removed the phrase from
     * its original lesson, in which case a lesson won't be found
     */
    // find the lesson which corresponds to this phrase
    /*for (QList<Lesson>::iterator it = lessons.begin(); it != lessons.end(); ++it) {
        if (it->contains(*p)) {
            currentLesson = it;
            withinLesson = true;
            break;
        }
    }
    if (currentLesson == lessons.end()) {
        // this phrase does not belong to any lesson
        withinLesson = false;
        qDebug() << "Could not enter thesaurus phrase into progress report because it was not associated with any lesson" << endl;
    }*/

    //set the current lesson to phrase's link.
    QString phraseLesson = p->getLesson();
    qDebug() << "phrase lesson: " << p->getLesson();
    currentLesson = std::find(lessons.begin(), lessons.end(), phraseLesson);
    if (currentLesson == lessons.end()) {
        qDebug() << "Could not find lesson for phrase.";
    }
    //currentLesson = lessons.begin();

    // set demonstrator video to selected phrase
    setDemoVideoFilename(p->getVideoFilename());
    // set cartoon to selected cartoon
    setCartoonFilename(p->getCartoonFilename());

    presentPhrase(*p);
}

/* Destructor
 * This calls the required constructors and closes the searchEngine.
 */
MainWindow::~MainWindow()
{
    /*
     * Delete actions
     */
    if (quizMeAction != 0) {
        delete quizMeAction;
        quizMeAction = 0;
    }

    delete ui;
    searchEngine.close();//close the search window if its open
    //end camera connection
    cvReleaseCapture(&camera);
    //vidRec.~VideoContainer();
}
